import os
import sys
import io
from pathlib import Path
import shutil # For file operations like copy/move/delete

# Import from sibling modules
from . import config
from . import decoder

def confirm(prompt: str) -> bool:
    """
    向用户获取 Y/N 确认。

    Args:
        prompt (str): 显示给用户的提示信息。

    Returns:
        bool: 如果用户确认 (yes)，返回 True；否则返回 False。
    """
    while True:
        try:
            # 模拟 Rust 的行为：打印提示符，不换行，并刷新输出缓冲区
            print(f"{prompt} (y/n): ", end='', flush=True)
            # 读取整行输入，以更好地处理缓冲输入
            response = sys.stdin.readline().strip().lower() # 读取、去除首尾空白、转小写
            if response == 'y':
                return True
            elif response == 'n':
                return False
            # 处理空输入（直接按 Enter）- 像 Rust 代码那样将其视为 'y'
            elif response == '':
                 # Rust 代码中关于单字节读取的逻辑有点复杂。
                 # `len == 1` 很可能意味着只有一个换行符，它将其视为 true。
                 # `len == 2 and buf[0] == 'y'` 涵盖了 'y\n'。
                 # 最简单的等效处理是将空输入视为 'y'。
                 return True
            else:
                # 如果输入不是 y/n/空，则要求重新输入
                print("请输入 'y' 或 'n'。")
        except EOFError: # 处理 stdin 被关闭的情况
            return False
        except KeyboardInterrupt: # 允许用户使用 Ctrl+C 中断操作
             print("\n操作已取消。")
             sys.exit(1) # 退出程序


def get_all_files(target: Path, recursive: bool) -> list[Path]:
    """
    根据目标路径和递归标志，查找所有需要处理的文件。

    Args:
        target (Path): 用户指定的目标文件或文件夹路径。
        recursive (bool): 是否递归查找子目录。

    Returns:
        list[Path]: 包含所有待处理文件 Path 对象的列表。
    """
    files = [] # 初始化文件列表
    if not target.exists(): # 检查路径是否存在
        print(f'无效: "{target}", 路径不存在。')
        return files

    if target.is_file(): # 如果目标是文件
        files.append(target) # 直接添加到列表
    elif target.is_dir(): # 如果目标是文件夹
        if recursive: # 如果需要递归
            # 使用 rglob 进行递归搜索
            # 在生成器中仅筛选文件，排除目录、符号链接等
            for item in target.rglob('*'): # 递归遍历所有子项
                if item.is_file(): # 只添加文件
                    files.append(item)
        else: # 如果不需要递归
            # 使用 iterdir 进行非递归搜索
            for item in target.iterdir(): # 遍历目录中的项
                if item.is_file(): # 只添加文件
                    files.append(item)
    else: # 处理其他类型，如符号链接、块设备等
        print(f'跳过: "{target}" (不是常规文件或目录)')

    return files


def decode_files(files: list[Path], cfg: config.argparse.Namespace) -> int:
    """
    根据配置解码文件列表中的文件。

    Args:
        files (list[Path]): 包含待解码文件路径的列表。
        cfg (config.argparse.Namespace): 解析后的命令行参数对象。

    Returns:
        int: 成功解码的文件数量。
    """
    count = 0 # 初始化成功计数器
    buffer_size = 16 * 1024 # 设置读取/写入缓冲区大小 (16 KiB)

    for file_path in files: # 遍历每个待处理的文件路径
        # 构造输出文件路径，将扩展名替换为 .mp3
        output_path = file_path.with_suffix(".mp3") # 注意：实际格式不一定是 mp3

        # --- 检查输出文件是否已存在 ---
        if output_path.exists():
            # 如果存在，询问用户是否覆盖
            if not confirm(f'文件 "{output_path}" 已存在。是否覆盖?'):
                print(f'跳过: "{file_path}" (输出文件已存在，用户选择不覆盖)')
                continue # 跳过当前文件

        try:
            # --- 打开输入文件 (二进制读取模式) ---
            with open(file_path, "rb") as f_in:
                # --- 尝试创建解码器 ---
                # decoder.new_decoder 会处理文件头的读取和验证
                dec = decoder.new_decoder(f_in)

                if dec is None: # 如果返回 None，说明文件格式无效或不支持
                    print(f'跳过: "{file_path}" (不是有效的 KGM 文件或不支持的格式)')
                    continue # 跳过当前文件

                # --- 打开输出文件 (二进制写入模式) 并进行解码写入 ---
                # 同时使用解码器和输出文件作为上下文管理器，确保它们被正确关闭
                with dec, open(output_path, "wb") as f_out:
                    while True:
                        # 从解码器读取解密后的数据块
                        chunk = dec.read(buffer_size)
                        if not chunk: # 如果读取到空数据，表示解码完成
                            break
                        # 将解密后的数据块写入输出文件
                        f_out.write(chunk)

            # --- 解码成功后，处理原始文件 ---
            if not cfg.keep_file: # 如果用户没有指定保留原文件
                try:
                    file_path.unlink() # 删除原始加密文件
                except OSError as e: # 处理删除文件时可能发生的错误
                    print(f'警告: 无法删除文件 "{file_path}", {e}')

            # 打印成功信息
            print(f'成功: "{file_path}" -> "{output_path}"')
            count += 1 # 成功计数加一

        # --- 异常处理 ---
        except FileNotFoundError:
             # 在处理过程中文件被移动或删除
             print(f'跳过: "{file_path}" (处理过程中文件未找到)')
             continue
        except PermissionError as e:
             # 没有读取或写入文件的权限
             print(f'跳过: "{file_path}" (权限错误: {e})')
             continue
        except OSError as e:
             # 其他文件系统相关错误 (如磁盘空间不足)
             print(f'处理 "{file_path}" 时发生错误: {e}')
             # 尝试清理可能已部分写入的输出文件
             if output_path.exists():
                 try:
                     output_path.unlink()
                 except OSError:
                     pass # 忽略清理错误
             continue
        except Exception as e: # 捕获其他在解码/IO中可能发生的意外错误
            print(f'处理 "{file_path}" 时发生意外错误: {e}')
            import traceback
            traceback.print_exc() # 打印详细的错误堆栈信息
             # 尝试清理
            if output_path.exists():
                 try:
                     output_path.unlink()
                 except OSError:
                     pass
            continue

    return count # 返回成功解码的文件总数

def run():
    """应用程序的主入口点。"""
    # 获取解析后的命令行配置
    cfg = config.get_config()
    # 将目标字符串转换为 Path 对象
    target_path = Path(cfg.target)

    # 获取所有需要处理的文件列表
    files_to_process = get_all_files(target_path, cfg.recursive)

    # 如果没有找到文件，则直接退出
    if not files_to_process:
        print("未找到需要处理的文件。")
        return

    # 打印找到的文件数量
    print(f"找到 {len(files_to_process)} 个文件")
    # 调用解码函数处理文件
    decoded_count = decode_files(files_to_process, cfg)
    # 打印最终完成结果
    print(f"完成 {decoded_count}/{len(files_to_process)}")

if __name__ == '__main__':
    # This allows running the main logic when the script is executed
    # For a proper package, you'd typically use entry points in setup.py
    run() 